package xiaojian.toolkit.netty.handler.codec.tcp.encode;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import xiaojian.toolkit.bean.CommonsHeader;
import xiaojian.toolkit.bean.bytebean.core.BeanFieldCodec;
import xiaojian.toolkit.bean.xip.annotation.SsipMessage;
import xiaojian.toolkit.util.ByteUtils;
import xiaojian.toolkit.util.Identifier;
import xiaojian.toolkit.util.IdentifierFactory;
import xiaojian.toolkit.util.MutableIdentifyable;

/**
 * 报文头采用xip格式进行编解码。
 * 
 * @author <a href="mailto:cxj2000@gmail.com">xiaojian.cao</a>
 *
 */
@ChannelHandler.Sharable
public class MixedXipEncoder extends MessageToByteEncoder<MutableIdentifyable> {

	private static final Logger logger = LoggerFactory.getLogger(MixedXipEncoder.class);

	private BeanFieldCodec xipBeanCodec = null;

	private int dumpBytes = 256;

	private boolean isDebugEnabled;

	/**
	 * @see io.netty.handler.codec.MessageToByteEncoder#encode(io.netty.channel.ChannelHandlerContext,
	 *      java.lang.Object, io.netty.buffer.ByteBuf)
	 */
	@Override
	protected void encode(ChannelHandlerContext ctx, MutableIdentifyable msg, ByteBuf out) throws Exception {
		SsipMessage smsg = msg.getClass().getAnnotation(SsipMessage.class);
		if (smsg == null) {
			throw new RuntimeException("invalid xip message, missing @SsipMessage.");
		}

		int msgCode = smsg.messageCode();
		if (msgCode == 0) {
			throw new RuntimeException("invalid xip message, missing msgCode.");
		}

		final Identifier<?> id = ((MutableIdentifyable) msg).getIdentification();
		if (logger.isDebugEnabled()) {
			logger.debug("encoding XipMessage {} to wrappedBuffer", msg);
		}
		if (null != id) {
			byte[] content = buildBytes(msg);

			// -- 组装头
			CommonsHeader header = new CommonsHeader();
			header.setMessageCode(msgCode);
			header.setIdBytes(IdentifierFactory.gerIdByte(id));

			// -- 写入数据。
			out.writeByte(header.getBasicVer());
			out.writeShort(header.getPayloadType());
			out.writeShort(header.getType());
			out.writeBytes(header.getIdBytes());
			out.writeInt(header.getReserved());
			out.writeInt(msgCode);
			out.writeInt(content.length);
			out.writeBytes(content);

			if (logger.isDebugEnabled() && isDebugEnabled) {
				logger.debug("cotent-->" + ByteUtils.bytesAsHexString(content, dumpBytes));
			}

		} else {
			if (logger.isWarnEnabled()) {
				logger.warn("{} is MutableIdentifyable but missing transactionId", msg);
			}
		}
	}

	private byte[] buildBytes(MutableIdentifyable msg) {
		return xipBeanCodec.encode(xipBeanCodec.getEncContextFactory().createEncContext(msg, msg.getClass(), null));
	}

	public BeanFieldCodec getXipBeanCodec() {
		return xipBeanCodec;
	}

	public void setXipBeanCodec(BeanFieldCodec xipBeanCodec) {
		this.xipBeanCodec = xipBeanCodec;
	}

	public int getDumpBytes() {
		return dumpBytes;
	}

	public void setDumpBytes(int dumpBytes) {
		this.dumpBytes = dumpBytes;
	}

	public boolean isDebugEnabled() {
		return isDebugEnabled;
	}

	public void setDebugEnabled(boolean isDebugEnabled) {
		this.isDebugEnabled = isDebugEnabled;
	}

}
